<?php
namespace froyo\cherry\Base;
use froyo\cherry\Exception\InvalidCallException;
use froyo\cherry\Exception\UnknownPropertyException;


class BaseObject{
    protected $_events = [];
    protected $className;
    protected $classNameFull;
    protected $classDirPath;
	function __construct($config=[]){
		BaseObject::configure($this,$config);
        $this->classNameFull = get_class($this);
        $this->className = substr(strrchr($this->classNameFull, "\\"), 1);
		$this->init_();
	}


    public function getClassName(){
        return $this->className;
    }

    public function getClassNameFull(){
        return $this->classNameFull;
    }

    public function getClassDirPath(){
        if(!$this->classDirPath)
        {
            $reflector = new \ReflectionClass($this);
            $this->classDirPath = dirname($reflector->getFileName());
        }
        return $this->classDirPath;
    }


    public static function loadConfig($config){
        $data = $config;
        if(is_array($config)){
            $isobject = false;
            if(isset($config['_class']))
            {
                $isobject = true;
                $class = $config['_class'];
                unset($config['_class']);
                if(!class_exists($class))
                {
                    throw new \Exception("config class ".$class."not exist", 1);
                }

            }
            foreach ($config as $k => $v) {
                $config[$k] = self::loadConfig($v);
            }
            if($isobject)
            {
                $data = new $class($config);
            }
            else
            {
                $data = $config;
            } 
        }
        
        return $data;
    }

    public static function configure($object, $properties)
    {
        foreach ($properties as $name => $value) {
            $object->$name = self::loadConfig($value);
        }

        return $object;
    }

	public function init_(){

	}

    public function load($data)
    {
        $this->setAttributes($data);
        return false;
    }


    public function setAttributes($values)
    {
        if (is_array($values)) {
            $attributes = $this->attributes();
            foreach ($values as $name => $value) {
                if (isset($attributes[$name])) {
                    $this->$name = $value;
                } 
            }
        }
    }

    public function attributes()
    {
        $class = new \ReflectionClass($this);
        $names = [];
        foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
            if (!$property->isStatic()) {
                $names[] = $property->getName();
            }
        }

        return $names;
    }

    //事件解除
    public function offEvent($name){

        if (empty($this->_events[$name])) {
            return false;
        }
        if ($handler === null) {
            unset($this->_events[$name]);
            return true;
        }

        // plain event names
        if (isset($this->_events[$name])) {
            $removed = false;
            foreach ($this->_events[$name] as $i => $event) {
                if ($event[0] === $handler) {
                    unset($this->_events[$name][$i]);
                    $removed = true;
                }
            }
            if ($removed) {
                $this->_events[$name] = array_values($this->_events[$name]);
                return $removed;
            }
        }
        return $removed;
    }

    //事件绑定
    public  function onEvent($class,$name,$handler,$append=true){

        if(!isset($this->_events[$name]))
        {
            $this->_events[$name] = [];
        }
        if ($append || empty($this->_events[$name])) {
            $this->_events[$name][] = [$handler, $data];
        } else {
            array_unshift($this->_events[$name], [$handler, $data]);
        }
    }


    //触发事件
    public function trigger($name,$event=null){
        if (empty($this->_events[$name])) {
            return;
        }
        $eventHandlers = [];

        if (!empty(self::$_events[$name])) {
            $eventHandlers = array_merge($eventHandlers, $this->_events[$name]);
        }
        if ($event === null) {
            $event = new Event();
        }
        $event->sender = $this;
        $event->handled = false;
        $event->name = $name;

        $classes = array_merge(
            [$class],
            class_parents($class, true),
            class_implements($class, true)
        );
        foreach ($eventHandlers as $handler) {
            $event->data = $handler[1];
            call_user_func($handler[0], $event);
            if ($event->handled) {
                return;
            }
        }
        Event::trigger($this, $name, $event);
    }


    public function __get($name)
    {
        $getter = 'get' . $name;
        if (method_exists($this, $getter)) {
            // read property, e.g. getName()
            return $this->$getter();
        }

        if (method_exists($this, 'set' . $name)) {
            throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
        }

        throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
    }

    public function __set($name, $value)
    {
        $setter = 'set' . $name;
        if (method_exists($this, $setter)) {
            // set property
            $this->$setter($value);
            return;
        } elseif (strncmp($name, 'on ', 3) === 0) {
            // on event: attach event handler
            $this->onEvent(trim(substr($name, 3)), $value);

            return;
        } 
        if (method_exists($this, 'get' . $name)) {
            throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
        }

        throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
    }

}


